﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//public struct PosInfo 
//{
//    public int posX;
//    public int posY;

//    public PosInfo(int x, int y) 
//    {
//        posX = x;
//        posY = y;
//    }
//}

public class AStarManager
{
    private static AStarManager instance;
    public static AStarManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new AStarManager();
            }
            return instance;
        }
    }

    public int[,] mapData = {
        {2,0,0,7,0,0,0,0,0,7,0},
        {0,0,0,7,7,7,0,0,0,7,0},
        {0,0,0,0,7,7,0,7,0,0,0},
        {0,0,0,0,0,7,0,7,0,7,0},
        {0,7,0,7,7,7,0,7,0,0,0},
        {0,0,0,0,0,0,0,7,0,7,0},
        {0,0,7,0,7,0,7,7,0,0,3}
    };

    public AStarNode[,] mapNodeList = new AStarNode[7,11];
    public AStarNode origin; //起点
    public AStarNode destination; //终点
    public List<AStarNode> openNodeList = new List<AStarNode>(); //开启点列表
    public List<AStarNode> closeNodeList = new List<AStarNode>(); //关闭点列表

    private int minX; //最小的x点
    private int maxX; //最大的x点
    private int minY; //最小的y点
    private int maxY; //最大的y点

    public void InitMapData()
    {
        openNodeList.Clear();
        closeNodeList.Clear();
        for (int i = 0; i < mapData.GetLength(0); i++) 
        {
            for (int j = 0; j < mapData.GetLength(1); j++) 
            {
                NodeType nodeType = NodeType.NodePass;
                if (mapData[i,j] == 1) 
                {
                }
                switch (mapData[i, j]) 
                {
                    case 7:
                        nodeType = NodeType.NodeStop;
                        break;
                    case 2:
                        nodeType = NodeType.NodeStart;
                        break;
                    case 3:
                        nodeType = NodeType.NodeEnd;
                        break;
                }
                //新建node，并加入mapNodeList中
                AStarNode aStarNode = new AStarNode(i, j, nodeType);
                mapNodeList[i, j] = aStarNode;
                if (nodeType == NodeType.NodeStart) 
                {
                    origin = aStarNode;
                }
                if (nodeType == NodeType.NodeEnd) 
                {
                    destination = aStarNode;
                }
            }
        }
        minX = 0;
        minY = 0;
        maxX = mapNodeList.GetLength(0) - 1; //行数
        maxY = mapNodeList.GetLength(1) - 1; //列数
        FindPath();
    }
    public void GetAroundNode(int x, int y,List<AStarNode> aroundNodeList) 
    {
        aroundNodeList.Clear();
        int startX = x - 1;
        int startY = y - 1;
        int endX = x + 1;
        int endY = y + 1;
        if (x == minX) 
        {
            startX = minX;
        }
        if (y == minY)
        {
            startY = minY;
        }
        if (x == maxX)
        {
            endX = maxX;
        }
        if (y == maxY)
        {
            endY = maxY;
        }
        for (int i = startX; i <= endX; i++) 
        {
            for (int j = startY; j <= endY; j++) 
            {
                //排除障碍物
                if (!(i == x && j == y) && mapNodeList[i, j].nodeType != NodeType.NodeStop)
                {
                    var existOpenNode = openNodeList.Find((xx) => xx.posX == i && xx.posY == j);
                    var existCloseNode = closeNodeList.Find((xx) => xx.posX == i && xx.posY == j);
                    if (existOpenNode == null && existCloseNode == null)
                    {
                        aroundNodeList.Add(mapNodeList[i, j]);
                    }
                }
            }
        }
    }

    public void FindPath()
    {
        bool isEnd = false;
        AStarNode curPoint;
        List<AStarNode> curAroundNodes = new List<AStarNode>();
        while (!isEnd)
        {
            curPoint = GetCurPoint();
            if (curPoint.h == 0 || (openNodeList.Count == 0 && closeNodeList.Count != 0))
            {
                //结束
                NodeListMove(curPoint);
                isEnd = true;
                break;
            }
            //获取当前点周围的点并计算寻路消耗
            GetAroundNode(curPoint.posX, curPoint.posY, curAroundNodes);
            if (curAroundNodes.Count == 0)
            {
                NodeListMove(curPoint);
                continue;
            }
            //排除在开始点列表中的点
            for (int i = curAroundNodes.Count - 1; i >= 0; i --) 
            {
                //计算寻路消耗
                //离起点的实际距离
                float g = Mathf.Sqrt(Mathf.Pow(curAroundNodes[i].posX - origin.posX, 2) + Mathf.Pow(curAroundNodes[i].posY - origin.posY, 2));
                //离终点的距离(曼哈顿街区算法)
                float h = Mathf.Abs(curAroundNodes[i].posX - destination.posX) + Mathf.Abs(curAroundNodes[i].posY - destination.posY);
                curAroundNodes[i].f = g + h;
                curAroundNodes[i].g = g;
                curAroundNodes[i].h = h;
                curAroundNodes[i].fatherNode = curPoint;
                //将该点加入到开启列表中
                openNodeList.Add(curAroundNodes[i]);
            }
            NodeListMove(curPoint);
        }
        //从end点或者最近点往上追溯父节点
        closeNodeList.Sort((x,y) => 
        {
            if (x.f < y.f)
            {
                return -1;
            }
            else
            {
                return 1;
            }
        });
        AStarNode recountNode = closeNodeList[0];
        List<AStarNode> resultNodes = new List<AStarNode>();
        while (recountNode.fatherNode != null)
        {
            resultNodes.Add(recountNode);
            recountNode = recountNode.fatherNode;
        }
        resultNodes.Add(origin);
        //resultNodes即为最后的寻路结果
        int[,] mapDataPlus = new int[7,11];
        for (int i = 0; i <= maxX; i++)
        {
            for (int j = 0; j <= maxY; j++) 
            {
                mapDataPlus[i,j] = mapData[i,j];
                var existNode = resultNodes.Find((elem) => elem.posX == i && elem.posY == j);
                if (existNode != null) 
                {
                    mapDataPlus[i, j] = 8;
                }
            }
            Debug.Log($"{mapDataPlus[i, 0]},{mapDataPlus[i, 1]},{mapDataPlus[i, 2]},{mapDataPlus[i, 3]},{mapDataPlus[i, 4]},{mapDataPlus[i, 5]},{mapDataPlus[i, 6]},{mapDataPlus[i, 7]},{mapDataPlus[i, 8]},{mapDataPlus[i, 9]},{mapDataPlus[i, 10]}");
        }
        Debug.Log("xx");
    }
    public AStarNode GetCurPoint() 
    {
        AStarNode curPoint = origin;

        if (openNodeList.Count > 0) 
        {
            //将开启列表中中的最低消耗点设置为当前点
            openNodeList.Sort((x, y) => {
                if (x.f < y.f)
                {
                    return -1;
                }
                else
                {
                    return 1;
                }
            });
            curPoint = openNodeList[0];
        }
        if (curPoint.f == 0)
        {
            float gs = Mathf.Sqrt(Mathf.Pow(curPoint.posX - origin.posX, 2) + Mathf.Pow(curPoint.posY - origin.posY, 2));
            //离终点的距离(曼哈顿街区算法)
            float hs = Mathf.Abs(curPoint.posX - destination.posX) + Mathf.Abs(curPoint.posY - destination.posY);
            curPoint.f = gs + hs;
            curPoint.g = gs;
            curPoint.h = hs;
        }
        return curPoint;
    }
    public void NodeListMove(AStarNode curPoint) 
    {
        if (openNodeList.Count > 0) 
        {
            openNodeList.RemoveAt(0);
        }
        closeNodeList.Add(curPoint);
    }
}
